import store from '@/store'
import {UPDATE_WS_STATUS} from "@/store/types";

class Socket {

	constructor(option) {
		// websocket实例
		this.$ws = null
		// store类型
		this.type = option.type || null
		// websocket状态
		this.isOpen = false
		// 重连状态
		this.isReconnect = false
		// websocket url
		this.wsURL = option.wsURL
		// 心跳计时器
		this.pingPongTimer = null
		// 心跳时间
		this.pingPongTime = Date.now()
		// 心跳间隔
		this.pingPongInterval = option.interval || 3000
		// 接收数据回调
		this.callback = option.callback || null
	}

	/**
	 * 初始化
	 */
	init = () => {
		if (this.$ws) {
			this.$ws.close()
		}
		this.setStatus(false)
		this.resetHeartBeat()
		if ('WebSocket' in window) {
			this.$ws = new WebSocket(this.wsURL)
			if (this.$ws.readyState === 0) {
				this.setStatus(false)
			}
		} else {
			this.setStatus(false)
			throw new Error('Your browser does not support websocket.')
		}
		this.$ws.addEventListener('open', this.onOpen)
		this.$ws.addEventListener('close', this.onClose)
		this.$ws.addEventListener('message', this.onMessage)
		this.$ws.addEventListener('error', this.onError)
	}

	/**
	 * 链接
	 * @param event
	 */
	onOpen = (event) => {
		this.setStatus(true)
		this.startHeartBeat()
		this.setStatus(true)
		console.log('websocket opened')
		const { channel } = store.state[this.type]
		for (let i = 0, len = channel.length; i < len; i ++ ) {
			this.sendMessage(channel[i])
		}
	}

	/**
	 * 关闭
	 * @param event
	 */
	onClose = (event) => {
		this.setStatus(false)
		this.resetHeartBeat()
		this.$ws.removeEventListener('open', this.onOpen)
		this.$ws.removeEventListener('close', this.onClose)
		this.$ws.removeEventListener('message', this.onMessage)
		this.$ws.removeEventListener('error', this.onError)
		this.$ws = null
		this.setStatus(false)
		console.log('websocket closed')
	}

	/**
	 * 更新当前ws实例状态和store里面ws实例状态
	 * @param status
	 */
	setStatus= (status) => {
		this.isOpen = status
		store.commit(`${this.type}/${UPDATE_WS_STATUS}`, status)
	}

	/**
	 * 手动关闭
	 */
	handleClose = () => {
		this.$ws.close()
		this.resetHeartBeat()
		this.setStatus(false)
		this.isReconnect = false
		console.log('websocket will manually stopped')
	}

	/**
	 *  错误重连
	 * @param err
	 */
	onError = (err) => {
		console.error('websocket closed', err)
		this.setStatus(false)
		this.resetHeartBeat()
		this.reConnect()
	}

	/**
	 * 消息处理
	 * @param event
	 * @returns {boolean}
	 */
	onMessage = (event) => {
		const {data} = event
		if (data && data === 'pong') {
			this.pingPongTime = Date.now()
			return false
		} else {
			this.callback && this.callback(data)
			// do something
		}
	}

	/**
	 * 发送消息
	 * @param msg
	 */
	sendMessage = (msg) => {
		if (this.isOpen) {
			this.$ws.send(msg)
		}
	}

	/**
	 * 重连
	 */
	reConnect = () => {
		console.log('websocket reconnect')
		this.init()
	}

	/**
	 * 心跳
	 */
	startHeartBeat = () => {
		this.resetHeartBeat()
		this.sendMessage('ping')
		this.pingPongTimer = setInterval(() => {
			this.sendMessage('ping')
			if (Date().now - this.pingPongTime > 10000) {
				console.log('No message has been received for 10 seconds, websocket will reconnect')
				this.isReconnect = true
				this.init()
			}
		}, this.pingPongInterval)
	}

	/**
	 * 重置心跳计时器
	 */
	resetHeartBeat = () => {
		clearInterval(this.pingPongTimer)
		this.pingPongTimer = null
		this.pingPongTime = Date.now()
	}
}

export default Socket
